home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / win / pascal / modialg.exe / MDIEXAM.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-11-30  |  37.4 KB  |  1,008 lines

  1. {**********************************************************************
  2.  
  3.     MDI Example Program               $Version$
  4.         $Author$            $Date$
  5.  
  6.         Copyright (c) 1991 Anthony M. Vitabile.
  7.         All rights reserved.
  8.  
  9.         Permission is hereby granted to all who desire to use this
  10.         source code in their programs provided the above copyright
  11.         is included in the program.
  12.  
  13.         Program Description
  14.  
  15.         This program is a demonstration of how to use the object types
  16.         defined in the MDITypes unit.  It defines four possible types
  17.         MDI children, all of which are descended from TMDIChild or
  18.         TMDIDialog.  It shows how to create MDI child windows which
  19.         look and act like modeless dialog boxes, as well as to do some
  20.         more conventional acts like drawing on an MDI child and editing
  21.         text in one.
  22.  
  23. **********************************************************************}
  24.  
  25. {$R MDIEXAM.RES}
  26. program MDIExample;
  27.   Uses MDITypes, WinTypes, WinProcs, WObjects, Strings;
  28.  
  29. {$D 'Copyright (c) 1991 Anthony M. Vitabile'}
  30. {$I MDIEXAM.INC}
  31.  
  32.   const
  33.     AppName  = 'MDIExample';
  34.     Dlg1Name = 'Dialog1';
  35.     Dlg2Name = 'Dialog2';
  36.     EditName = 'MDIEdit';
  37.     RandName = 'MDIRect';
  38.  
  39.     EditPos  = 2;
  40.     InitPos  = 1;
  41.     RectPos  = 1;
  42.  
  43.   type
  44.     ChildNames      = (Dialog1, Dialog2, RandRect, EditCtrl);
  45.  
  46.     TitleArray      = array [Dialog1 .. EditCtrl] of PChar;
  47.  
  48.     PDialog1        = ^TDialog1;
  49.     PDialog2        = ^TDialog2;
  50.     PDlg1XferBuffer = ^Dlg1XferBuffer;
  51.     PDlg2XferBuffer = ^Dlg2XferBuffer;
  52.     PMDIApplication = ^TMDIApplication;
  53.     PMDIDialog1     = ^TMDIDialog1;
  54.     PMDIDialog2     = ^TMDIDialog2;
  55.     PMDIEditChild   = ^TMDIEditChild;
  56.     PMyMDIFrame     = ^TMyMDIFrame;
  57.     PRandRect       = ^TRandRect;
  58.  
  59.     Dlg1XferBuffer  = record
  60.                         Number :  array [0 ..  6] of char;
  61.                         Name   ,
  62.                         Company,
  63.                         Address,
  64.                         City   :  array [0 .. 40] of char;
  65.                         State  :  array [0 ..  3] of char;
  66.                         ZipCode:  array [0 .. 11] of char
  67.                       end;
  68.  
  69.     Dlg2XferBuffer  = record
  70.                         Number:  array [0 ..  6] of char;
  71.                         Field1:  array [0 .. 40] of char;
  72.                         Field2:  array [0 .. 80] of char
  73.                       end;
  74.  
  75.     TDialog1        = object (TDlgWindow)
  76.                         Static :  PStatic;
  77.                         Name   ,
  78.                         Company,
  79.                         Address,
  80.                         City   ,
  81.                         State  ,
  82.                         ZipCode:  PEdit;
  83.  
  84.                         destructor Done;
  85.                           virtual;
  86.                         constructor Init(AParent:  PWindowsObject;
  87.                                          AName  :  PChar;
  88.                                          Buffer :  Pointer);
  89.                       end;
  90.  
  91.     TDialog2        = object (TDlgWindow)
  92.                         Static:  PStatic;
  93.                         Field1,
  94.                         Field2:  PEdit;
  95.  
  96.                         destructor Done;
  97.                           virtual;
  98.                         constructor Init(AParent:  PWindowsObject;
  99.                                          AName  :  PChar;
  100.                                          Buffer :  Pointer);
  101.                       end;
  102.  
  103.     TMDIApplication = object (TApplication)
  104.                         EditMenu,
  105.                         RectMenu:  HMenu;
  106.  
  107.                         destructor Done;
  108.                           virtual;
  109.                         procedure InitInstance;
  110.                           virtual;
  111.                         procedure InitMainWindow;
  112.                           virtual;
  113.                         function ProcessAppMsg(var Message:  TMsg):  boolean;
  114.                           virtual;
  115.                       end;
  116.  
  117.     TMDIDialog1     = object (TMDIDialog)
  118.                         destructor Done;
  119.                           virtual;
  120.                         constructor Init(AParent:  PWindowsObject;
  121.                                          ATitle :  PChar;
  122.                                          ANumber:  integer);
  123.                         function InitDialog:  PDlgWindow;
  124.                           virtual;
  125.                         function GetClassName:  PChar;
  126.                           virtual;
  127.                         procedure GetWindowClass(var AWndClass:  TWndClass);
  128.                           virtual;
  129.                         procedure SetupWindow;
  130.                           virtual;
  131.                         procedure wmInitMenuPopup(var Msg:  TMessage);
  132.                           virtual wm_First + wm_InitMenuPopup;
  133.                       end;
  134.  
  135.     TMDIDialog2     = object (TMDIDialog)
  136.                         destructor Done;
  137.                           virtual;
  138.                         constructor Init(AParent:  PWindowsObject;
  139.                                          ATitle :  PChar;
  140.                                          ANumber:  integer);
  141.                         function InitDialog:  PDlgWindow;
  142.                           virtual;
  143.                         function GetClassName:  PChar;
  144.                           virtual;
  145.                         procedure GetWindowClass(var AWndClass:  TWndClass);
  146.                           virtual;
  147.                         procedure SetupWindow;
  148.                           virtual;
  149.                         procedure wmInitMenuPopup(var Msg:  TMessage);
  150.                           virtual wm_First + wm_InitMenuPopup;
  151.                       end;
  152.  
  153.     TMDIEditChild   = object(TMDIChild)
  154.                         TheEdit:  PEdit;
  155.  
  156.                         destructor  Done;
  157.                           virtual;
  158.                         constructor Init(AParent:  PWindowsObject;
  159.                                          ATitle :  PChar;
  160.                                          ANumber:  integer);
  161.                         function GetClassName:  PChar;
  162.                           virtual;
  163.                         procedure GetWindowClass(var AWndClass:  TWndClass);
  164.                           virtual;
  165.                         procedure wmInitMenuPopup(var Msg:  TMessage);
  166.                           virtual wm_First + wm_InitMenuPopup;
  167.                         procedure wmSetFocus(var Msg:  TMessage);
  168.                           virtual wm_First + wm_SetFocus;
  169.                         procedure wmSize(var Msg:  TMessage);
  170.                           virtual wm_First + wm_Size;
  171.                       end;
  172.  
  173.     TMyMDIFrame    = object (TMDIFrame)
  174.                         NoChildren:  integer;
  175.                         DialogType:  ChildNames;
  176.  
  177.                         constructor Init(ATitle:  PChar;
  178.                                          APos  :  integer);
  179.                         function  GetClassName:  PChar;
  180.                           virtual;
  181.                         procedure GetWindowClass(var AWndClass:  TWndClass);
  182.                           virtual;
  183.                         function  InitChild:  PWindowsObject;
  184.                           virtual;
  185.                         procedure SetupWindow;
  186.                           virtual;
  187.                         procedure idCloseChild(var Msg:  TMessage);
  188.                           virtual cm_First + id_CloseChild;
  189.                         procedure idDialog1(var Msg:  TMessage);
  190.                           virtual cm_First + id_Dialog1;
  191.                         procedure idDialog2(var Msg:  TMessage);
  192.                           virtual cm_First + id_Dialog2;
  193.                         procedure idEditCtrl(var Msg:  TMessage);
  194.                           virtual cm_First + id_EditCtrl;
  195.                         procedure idRandRect(var Msg:  TMessage);
  196.                           virtual cm_First + id_RandRect;
  197.                       end;
  198.  
  199.     TRandRect       = object (TMDIChild)
  200.                         constructor Init(AParent:  PWindowsObject;
  201.                                          ATitle :  PChar;
  202.                                          ANumber:  integer);
  203.                         function GetClassName:  PChar;
  204.                           virtual;
  205.                         procedure SetupWindow;
  206.                           virtual;
  207.                         procedure wmDestroy(var Msg:  TMessage);
  208.                           virtual wm_First + wm_Destroy;
  209.                         procedure wmPaint(var Msg:  TMessage);
  210.                           virtual wm_First + wm_Paint;
  211.                         procedure wmTimer(var Msg:  TMessage);
  212.                           virtual wm_First + wm_Timer;
  213.                       end;
  214.  
  215.   const
  216.     ChildTitles:  TitleArray = ('Dialog 1, Child #',
  217.                                 'Dialog 2, Child #',
  218.                                 'Random Rectangles, Child #',
  219.                                 'Editor, Child #');
  220.  
  221.   var
  222.     MDIApplication:  TMDIApplication;
  223.  
  224. {**********************************************************************
  225.  
  226.     This is a generic routine for initializing the Edit menu for
  227.         any menu that has one and for any window that has an edit
  228.         control.  It checks the edit control to see if it's able
  229.         to undo an edit, tests for text on the clipboard, etc.
  230.  
  231. **********************************************************************}
  232.  
  233.   procedure InitEditMenu(Edit:  HWnd; var Msg:  TMessage);
  234.     var
  235.       Enable:  word;
  236.       Select:  LongInt;
  237.  
  238.     begin    { InitEditMenu }
  239.       if SendMessage(Edit, em_CanUndo, 0, 0) <> 0
  240.         then Enable := mf_Enabled
  241.         else Enable := mf_Grayed;
  242.       EnableMenuItem(Msg.wParam, cm_EditUndo , Enable or mf_ByCommand);
  243.       if IsClipboardFormatAvailable(cf_Text)
  244.         then Enable := mf_Enabled
  245.         else Enable := mf_Grayed;
  246.       EnableMenuItem(Msg.wParam, cm_EditPaste, Enable or mf_ByCommand);
  247.       Select := SendMessage(Edit, em_GetSel, 0, 0);
  248.       if LoWord(Select) = HiWord(Select)
  249.         then Enable := MF_Grayed
  250.         else Enable := MF_Enabled;
  251.       EnableMenuItem(Msg.wParam, cm_EditCut  , Enable or mf_ByCommand);
  252.       EnableMenuItem(Msg.wParam, cm_EditCopy , Enable or mf_ByCommand);
  253.       EnableMenuItem(Msg.wParam, cm_EditClear, Enable or mf_ByCommand);
  254.       Msg.result := 0
  255.     end        { InitEditMenu };
  256.  
  257. {**********************************************************************
  258.  
  259.     TDialog1 methods
  260.  
  261.         Done destructor.  This method frees all child objects
  262.         associated with the dialog box instance and then destroys
  263.         itself.
  264.  
  265. **********************************************************************}
  266.  
  267.   destructor TDialog1.Done;
  268.     begin    { TDialog1.Done }
  269.       dispose(Static , Done);
  270.       dispose(Name   , Done);
  271.       dispose(Address, Done);
  272.       dispose(Company, Done);
  273.       dispose(City   , Done);
  274.       dispose(State  , Done);
  275.       dispose(ZipCode, Done);
  276.       TDlgWindow.Done
  277.     end        { TDialog1.Done };
  278.  
  279. {**********************************************************************
  280.  
  281.     Init constructor.  This method builds a modeless dialog box.
  282.         It first calls TDlgWindow.Init to initialize all of the fields
  283.         TDialog1 inherited.  It then creates OWL child control objects
  284.         that allow the activation of the transfer buffer feature.
  285.  
  286. **********************************************************************}
  287.  
  288.   constructor TDialog1.Init(AParent:  PWindowsObject;
  289.                             AName  :  PChar;
  290.                             Buffer :  Pointer);
  291.     begin    { TDialog1.Init }
  292.       TDlgWindow.Init(AParent, AName);
  293.       TransferBuffer := Buffer;
  294.       Static  := New(PStatic, InitResource(@Self, id_ChildNumber,  6));
  295.       Name    := New(PEdit  , InitResource(@Self, id_Name       , 40));
  296.       Company := New(PEdit  , InitResource(@Self, id_Company    , 40));
  297.       Address := New(PEdit  , InitResource(@Self, id_Address    , 40));
  298.       City    := New(PEdit  , InitResource(@Self, id_City       , 40));
  299.       State   := New(PEdit  , InitResource(@Self, id_State      ,  3));
  300.       ZipCode := New(PEdit  , InitResource(@Self, id_ZipCode    , 11));
  301.       Static ^.EnableTransfer;
  302.       Name   ^.EnableTransfer;
  303.       Address^.EnableTransfer;
  304.       Company^.EnableTransfer;
  305.       City   ^.EnableTransfer;
  306.       State  ^.EnableTransfer;
  307.       ZipCode^.EnableTransfer;
  308.       EnableKBHandler
  309.     end        { TDialog1.Init };
  310.  
  311. {**********************************************************************
  312.  
  313.     TDialog2 methods
  314.  
  315.         Done destructor.  This method frees all child objects
  316.         associated with the dialog box instance and then destroys
  317.         itself.
  318.  
  319. **********************************************************************}
  320.  
  321.   destructor TDialog2.Done;
  322.     begin    { TDialog2.Done }
  323.       dispose(Static, Done);
  324.       dispose(Field1, Done);
  325.       dispose(Field2, Done);
  326.       TDlgWindow.Done
  327.     end        { TDialog2.Done };
  328.  
  329. {**********************************************************************
  330.  
  331.     Init constructor.  This method builds a modeless dialog box.
  332.         It first calls TDlgWindow.Init to initialize all of the fields
  333.         TDialog1 inherited.  It then creates OWL child control objects
  334.         that allow the activation of the transfer buffer feature.
  335.  
  336. **********************************************************************}
  337.  
  338.   constructor TDialog2.Init(AParent:  PWindowsObject;
  339.                             AName  :  PChar;
  340.                             Buffer :  Pointer);
  341.     begin    { TDialog2.Init }
  342.       TDlgWindow.Init(AParent, AName);
  343.       TransferBuffer := Buffer;
  344.       Static := New(PStatic, InitResource(@Self, id_ChildNumber,  6));
  345.       Field1 := New(PEdit  , InitResource(@Self, id_Field1     , 40));
  346.       Field2 := New(PEdit  , InitResource(@Self, id_Field2     , 80));
  347.       Static^.EnableTransfer;
  348.       Field1^.EnableTransfer;
  349.       Field2^.EnableTransfer;
  350.       EnableKBHandler
  351.     end        { TDialog2.Init };
  352.  
  353. {**********************************************************************
  354.  
  355.     TMDIApplication methods
  356.  
  357.         Done destructor.  This method frees the child menus we've
  358.         created in the resource file & loaded.  This procedure is
  359.         called after the message loop has exitted, so all child windows
  360.         that would use these menus are long dead.
  361.  
  362. **********************************************************************}
  363.  
  364.   destructor TMDIApplication.Done;
  365.     begin    { TMDIApplication.Done }
  366. {     DestroyMenu(EditMenu);
  367.       DestroyMenu(RectMenu); }
  368.       TApplication.Done
  369.     end        { TMDIApplication.Done };
  370.  
  371. {**********************************************************************
  372.  
  373.     InitInstance.  This method is called whenever an application
  374.         starts running in order to perform initialization for the
  375.         instance currently starting up.  This method first loads
  376.         the menus for the MDI child windows from the resource file.
  377.         It then performs the rest of the instance initialization by
  378.         calling the ancestor method.
  379.  
  380. **********************************************************************}
  381.  
  382.   procedure TMDIApplication.InitInstance;
  383.     begin    { TMDIApplication.InitInstance }
  384.       EditMenu  := LoadMenu(HInstance, EditName);
  385.       RectMenu  := LoadMenu(HInstance, RandName);
  386.       TApplication.InitInstance;
  387.       HAccTable := LoadAccelerators(HInstance, AppName)
  388.     end        { TMDIApplication.InitInstance };
  389.  
  390. {**********************************************************************
  391.  
  392.     This method creates the program's main window.  In this case,
  393.         this is the Frame window, descended from TMDIFrame.  It creates
  394.         the OWL window object & saves the pointer to it in the
  395.         application object's MainWindow field.
  396.  
  397. **********************************************************************}
  398.  
  399.   procedure TMDIApplication.InitMainWindow;
  400.     begin    { TMDIApplication.InitMainWindow }
  401.       MainWindow := New(PMyMDIFrame, Init(AppName, InitPos))
  402.     end        { TMDIApplication.InitMainWindow };
  403.  
  404. {**********************************************************************
  405.  
  406.     Performs special handling for the message last retrieved.
  407.         Translates keyboard input messages into control selections or
  408.         command messages, when appropriate.  Dispatches message, if
  409.         translated.  This method changes the order in which testing
  410.         is performed so that MDI accelerators are performed first.
  411.  
  412. **********************************************************************}
  413.  
  414.   function TMDIApplication.ProcessAppMsg(var Message:  TMsg):  boolean;
  415.     begin    { TMDIApplication.ProcessAppMsg }
  416.       ProcessAppMsg := ProcessMDIAccels(Message) or
  417.                        ProcessDlgMsg   (Message) or
  418.                        ProcessAccels   (Message)
  419.     end        { TMDIApplication.ProcessAppMsg };
  420.  
  421. {**********************************************************************
  422.  
  423.     TMDIDialog1 methods
  424.  
  425.         Done destructor.  This routine destroys an instance of
  426.         TMDIDialog1.  It first frees the transfer buffer, then it calls
  427.         TMDIDialog.Done to free the rest of the object.
  428.  
  429. **********************************************************************}
  430.  
  431.   destructor TMDIDialog1.Done;
  432.     begin    { TMDIDialog1.Done }
  433.       FreeMem(TheDialog^.TransferBuffer, sizeof(Dlg1XferBuffer));
  434.       TMDIDialog.Done
  435.     end        { TMDIDialog1.Done };
  436.  
  437. {**********************************************************************
  438.  
  439.         Init constructor.  This routine initializes the fields we've
  440.         added to the inherited set and then calls the inherited
  441.         constructor to build the window.
  442.  
  443. **********************************************************************}
  444.  
  445.   constructor TMDIDialog1.Init(AParent:  PWindowsObject;
  446.                                ATitle :  PChar;
  447.                                ANumber:  integer);
  448.     begin    { TMDIDialog1.Init }
  449.       with MDIApplication do
  450.         TMDIDialog.Init(AParent, ATitle, EditMenu, EditPos);
  451.       Attr.ID := ANumber
  452.     end        { TMDIDialog1.Init };
  453.  
  454. {**********************************************************************
  455.  
  456.     InitDialog method.  This method is an override of the TMDIDialog
  457.         method.  It allocates memory for a transfer buffer for the
  458.         dialog box, then initializes the buffer.  It finally creates
  459.         the dialog box OWL object & returns its address to the caller.
  460.  
  461. **********************************************************************}
  462.  
  463.   function TMDIDialog1.InitDialog:  PDlgWindow;
  464.     var
  465.       Buffer:  PDlg1XFerBuffer;
  466.  
  467.     begin    { TMDIDialog1.InitDialog }
  468.       GetMem(Buffer, sizeof(Dlg1XferBuffer));
  469.       FillChar(Buffer^, sizeof(Dlg1XferBuffer), 0);
  470.       InitDialog := PDlgWindow(New(PDialog1, Init(@Self, Dlg1Name, Buffer)))
  471.     end        { TMDIDialog1.InitDialog };
  472.  
  473. {**********************************************************************
  474.  
  475.     These two methods are standard for changing the window class's
  476.         characteristics.  In this case, we name the class "Dialog1".
  477.         We also set the class's icon to the icon we created in the
  478.         resource file.  This allows us to use the standard windows
  479.         code for dealing with a minimized instance of this class!
  480.  
  481. **********************************************************************}
  482.  
  483.   function TMDIDialog1.GetClassName:  PChar;
  484.     begin    { TMDIDialog1.GetClassName }
  485.       GetClassName := Dlg1Name
  486.     end        { TMDIDialog1.GetClassName };
  487.  
  488.   procedure TMDIDialog1.GetWindowClass(var AWndClass:  TWndClass);
  489.     begin    { TMDIDialog1.GetWindowClass }
  490.       TMDIChild.GetWindowClass(AWndClass);
  491.       AWndClass.hIcon := LoadIcon(HInstance, Dlg1Name)
  492.     end        { TMDIDialog1.GetWindowClass };
  493.  
  494. {**********************************************************************
  495.  
  496.     This method sets up the dialog window's child number static
  497.         field so that it has the right number.
  498.  
  499. **********************************************************************}
  500.  
  501.   procedure TMDIDialog1.SetupWindow;
  502.     var
  503.       NumStr:  string[6];
  504.  
  505.     begin    { TMDIDialog1.SetupWindow }
  506.       TMDIDialog.SetupWindow;
  507.       Str(Attr.ID:1, NumStr);
  508.       StrPCopy(PDlg1XferBuffer(TheDialog^.TransferBuffer)^.Number, NumStr);
  509.       with PDialog1(TheDialog)^ do
  510.         Static^.Transfer(TransferBuffer, tf_SetData)
  511.     end        { TMDIDialog1.SetupWindow };
  512.  
  513. {**********************************************************************
  514.  
  515.     This method sets up the edit menu to reflect the ability of
  516.         any edit control to fulfill an editing command.
  517.  
  518. **********************************************************************}
  519.  
  520.   procedure TMDIDialog1.wmInitMenuPopup(var Msg:  TMessage);
  521.     var
  522.       Wnd:  HWnd;
  523.  
  524.     begin    { TMDIDialog1.wmInitMenuPopup }
  525.       if Msg.lParam = 1
  526.         then
  527.           begin
  528.             Wnd := GetFocus;
  529.             if IsChild(TheDialog^.HWindow, Wnd)
  530.               then InitEditMenu(Wnd, Msg)
  531.           end;
  532.       Msg.result := 0
  533.     end        { TMDIDialog1.wmInitMenuPopup };
  534.  
  535. {**********************************************************************
  536.  
  537.     TMDIDialog2 methods
  538.  
  539.         Done destructor.  This routine destroys an instance of
  540.         TMDIDialog2.  It first frees the transfer buffer, then it calls
  541.         TMDIDialog.Done to free the rest of the object.
  542.  
  543. **********************************************************************}
  544.  
  545.   destructor TMDIDialog2.Done;
  546.     begin    { TMDIDialog2.Done }
  547.       FreeMem(TheDialog^.TransferBuffer, sizeof(Dlg2XferBuffer));
  548.       TMDIDialog.Done
  549.     end        { TMDIDialog2.Done };
  550.  
  551. {**********************************************************************
  552.  
  553.         Init constructor.  This routine initializes the fields we've
  554.         added to the inherited set and then calls the inherited
  555.         constructor to build the window.
  556.  
  557. **********************************************************************}
  558.  
  559.   constructor TMDIDialog2.Init(AParent:  PWindowsObject;
  560.                                ATitle :  PChar;
  561.                                ANumber:  integer);
  562.     begin    { TMDIDialog2.Init }
  563.       with MDIApplication do
  564.         TMDIDialog.Init(AParent, ATitle, EditMenu, EditPos);
  565.       Attr.ID := ANumber
  566.     end        { TMDIDialog2.Init };
  567.  
  568. {**********************************************************************
  569.  
  570.     InitDialog method.  This method is an override of the TMDIDialog
  571.         method.  It allocates memory for a transfer buffer for the
  572.         dialog box, then initializes the buffer.  It finally creates
  573.         the dialog box OWL object & returns its address to the caller.
  574.  
  575. **********************************************************************}
  576.  
  577.   function TMDIDialog2.InitDialog:  PDlgWindow;
  578.     var
  579.       Buffer:  PDlg2XferBuffer;
  580.  
  581.     begin    { TMDIDialog2.InitDialog }
  582.       GetMem(Buffer, sizeof(Dlg2XferBuffer));
  583.       FillChar(Buffer^, sizeof(Dlg2XferBuffer), 0);
  584.       InitDialog := PDlgWindow(New(PDialog2, Init(@Self, Dlg2Name, Buffer)))
  585.     end        { TMDIDialog2.InitDialog };
  586.  
  587. {**********************************************************************
  588.  
  589.     These two methods are standard for changing the window class's
  590.         characteristics.  In this case, we name the class "Dialog2".
  591.         We also set the class's icon to the icon we created in the
  592.         resource file.  This allows us to use the standard windows
  593.         code for dealing with a minimized instance of this class!
  594.  
  595. **********************************************************************}
  596.  
  597.   function TMDIDialog2.GetClassName:  PChar;
  598.     begin    { TMDIDialog2.GetClassName }
  599.       GetClassName := Dlg2Name
  600.     end        { TMDIDialog2.GetClassName };
  601.  
  602.   procedure TMDIDialog2.GetWindowClass(var AWndClass:  TWndClass);
  603.     begin    { TMDIDialog2.GetWindowClass }
  604.       TMDIChild.GetWindowClass(AWndClass);
  605.       AWndClass.hIcon := LoadIcon(HInstance, Dlg2Name)
  606.     end        { TMDIDialog2.GetWindowClass };
  607.  
  608. {**********************************************************************
  609.  
  610.     This method sets up the dialog window's child number static
  611.         field so that it has the right number.
  612.  
  613. **********************************************************************}
  614.  
  615.   procedure TMDIDialog2.SetupWindow;
  616.     var
  617.       NumStr:  string[6];
  618.  
  619.     begin    { TMDIDialog2.SetupWindow }
  620.       TMDIDialog.SetupWindow;
  621.       Str(Attr.ID:1, NumStr);
  622.       StrPCopy(PDlg1XferBuffer(TheDialog^.TransferBuffer)^.Number, NumStr);
  623.       with PDialog2(TheDialog)^ do
  624.         Static^.Transfer(TransferBuffer, tf_SetData)
  625.     end        { TMDIDialog2.SetupWindow };
  626.  
  627. {**********************************************************************
  628.  
  629.     This method sets up the edit menu to reflect the ability of
  630.         any edit control to fulfill an editing command.
  631.  
  632. **********************************************************************}
  633.  
  634.   procedure TMDIDialog2.wmInitMenuPopup(var Msg:  TMessage);
  635.     var
  636.       Wnd:  HWnd;
  637.  
  638.     begin    { TMDIDialog2.wmInitMenuPopup }
  639.       if Msg.lParam = 1
  640.         then
  641.           begin
  642.             Wnd := GetFocus;
  643.             if IsChild(TheDialog^.HWindow, Wnd)
  644.               then InitEditMenu(Wnd, Msg)
  645.           end;
  646.       Msg.result := 0
  647.     end        { TMDIDialog2.wmInitMenuPopup };
  648.  
  649. {**********************************************************************
  650.  
  651.     TMDIEditChild methods
  652.  
  653.         Done destructor.  It first destroys the edit control child
  654.         window and then destroys itself.
  655.  
  656. **********************************************************************}
  657.  
  658.   destructor TMDIEditChild.Done;
  659.     begin    { TMDIEditChild.Done }
  660.       dispose(TheEdit, Done);
  661.       TMDIChild.Done
  662.     end        { TMDIEditChild.Done };
  663.  
  664. {**********************************************************************
  665.  
  666.         Init constructor.  This routine initializes the fields we've
  667.         added to the inherited set and then calls the inherited
  668.         constructor to build the window.
  669.  
  670. **********************************************************************}
  671.  
  672.   constructor TMDIEditChild.Init(AParent:  PWindowsObject;
  673.                                  ATitle :  PChar;
  674.                                  ANumber:  integer);
  675.     begin    { TMDIEditChild.Init }
  676.       with MDIApplication do
  677.         TMDIChild.Init(AParent, ATitle, EditMenu, EditPos);
  678.       Attr.ID := ANumber;
  679.       TheEdit := New(PEdit, Init(@Self, 100, nil, 0, 0, 0, 0, 0, TRUE))
  680.     end        { TMDIEditChild.Init };
  681.  
  682. {**********************************************************************
  683.  
  684.     These two methods are standard for changing the window class's
  685.         characteristics.  In this case, we name the class "EditCtrl".
  686.         We also set the class's icon to the icon we created in the
  687.         resource file.  This allows us to use the standard windows
  688.         code for dealing with a minimized instance of this class!
  689.  
  690. **********************************************************************}
  691.  
  692.   function TMDIEditChild.GetClassName:  PChar;
  693.     begin    { TMDIEditChild.GetClassName }
  694.       GetClassName := EditName
  695.     end        { TMDIEditChild.GetClassName };
  696.  
  697.   procedure TMDIEditChild.GetWindowClass(var AWndClass:  TWndClass);
  698.     begin    { TMDIDialog1.GetWindowClass }
  699.       TWindow.GetWindowClass(AWndClass);
  700.       AWndClass.hIcon := LoadIcon(HInstance, EditName)
  701.     end        { TMDIEditChild.GetWindowClass };
  702.  
  703. {**********************************************************************
  704.  
  705.     This method sets up the edit menu to reflect the ability of
  706.         any edit control to fulfill an editing command.
  707.  
  708. **********************************************************************}
  709.  
  710.   procedure TMDIEditChild.wmInitMenuPopup(var Msg:  TMessage);
  711.     begin    { TMDIEditChild.wmInitMenuPopup }
  712.       if Msg.lParam = 1
  713.         then InitEditMenu(TheEdit^.HWindow, Msg);
  714.       Msg.result := 0
  715.     end        { TMDIEditChild.wmInitMenuPopup };
  716.  
  717. {**********************************************************************
  718.  
  719.         The window has received the input focus.  We don't want it.
  720.     This method passes the focus to its child edit control window.
  721.  
  722. **********************************************************************}
  723.  
  724.   procedure TMDIEditChild.wmSetFocus(var Msg:  TMessage);
  725.     begin    { TMDIEditChild.wmSetFocus }
  726.       if TheEdit^.HWindow <> 0
  727.         then SetFocus(TheEdit^.HWindow);
  728.       Msg.result := 0
  729.     end        { TMDIEditChild.wmSetFocus };
  730.  
  731. {**********************************************************************
  732.  
  733.     This method makes sure that the edit child control window
  734.         always occupies the entire area of the MDI child window.
  735.  
  736. **********************************************************************}
  737.  
  738.   procedure TMDIEditChild.wmSize(var Msg:  TMessage);
  739.     begin    { TMDIEditChild.wmSize }
  740.       if TheEdit^.HWindow <> 0
  741.         then MoveWindow(TheEdit^.HWindow, 0, 0, LoWord(Msg.lParam),
  742.                                                 HiWord(Msg.lParam), TRUE);
  743.       TMDIChild.wmSize(Msg)
  744.     end        { TMDIEditChild.wmSize };
  745.  
  746. {**********************************************************************
  747.  
  748.     TMDIFrame methods
  749.  
  750.         Init constructor.  This routine initializes the fields we've
  751.         added to the inherited set and then calls the inherited
  752.         constructor to build the window.
  753.  
  754. **********************************************************************}
  755.  
  756.   constructor TMyMDIFrame.Init(ATitle:  PChar;
  757.                                APos  :  integer);
  758.     begin    { TMyMDIFrame.Init }
  759.       TMDIFrame.Init(ATitle, 0);
  760.       ChildMenuPos := APos;
  761.       NoChildren   := 0;
  762.       DialogType   := Dialog1
  763.     end        { TMyMDIFrame.Init };
  764.  
  765.   procedure TMyMDIFrame.SetupWindow;
  766.     begin    { TMyMDIFrame.SetupWindow }
  767.       TMDIFrame.SetupWindow;
  768.       Attr.Menu := GetMenu(HWindow)
  769.     end        { TMyMDIFrame.SetupWindow };
  770.  
  771. {**********************************************************************
  772.  
  773.     These two methods are standard for changing the window class's
  774.         characteristics.  In this case, we name the class "MDIExample".
  775.         We also set the class's icon to the icon we created in the
  776.         resource file.
  777.  
  778. **********************************************************************}
  779.  
  780.   function TMyMDIFrame.GetClassName:  PChar;
  781.     begin    { TMyMDIFrame.GetClassName }
  782.       GetClassName := AppName
  783.     end        { TMyMDIFrame.GetClassName };
  784.  
  785.   procedure TMyMDIFrame.GetWindowClass(var AWndClass:  TWndClass);
  786.     begin    { TMyMDIFrame.GetWindowClass }
  787.       TMDIFrame.GetWindowClass(AWndClass);
  788.       AWndClass.lpszMenuName  := AppName;
  789.       AWndClass.hbrBackground := color_AppWorkspace + 1;
  790.       AWndClass.hIcon         := LoadIcon(HInstance, AppName)
  791.     end        { TMyMDIFrame.GetWindowClass };
  792.  
  793. {**********************************************************************
  794.  
  795.     These methods handle menu command selection.  They get the
  796.         proper events rolling whenever the user uses one of the commands.
  797.  
  798.         The idea is that when the user specifies that a particular
  799.         type of child window should be created, we save an apropriate
  800.         value in the frame window's DialogType field.  This records
  801.         exactly what we should be doing.
  802.  
  803.         Other commands are implemented in other ways.
  804.  
  805. **********************************************************************}
  806.  
  807.   procedure TMyMDIFrame.idCloseChild(var Msg:  TMessage);
  808.     var
  809.       NChild:  integer;
  810.       Handle:  HWnd;
  811.       Child :  PWindowsObject;
  812.  
  813.     begin    { TMyMDIFrame.idCloseChild }
  814.       Handle := LoWord(SendMessage(GetClient^.HWindow, wm_MDIGetActive, 0, 0));
  815.       Child  := GetChild(Handle);
  816.       CloseChild(Child);
  817.       dec(NoChildren)
  818.     end        { TMyMDIFrame.idCloseChild };
  819.  
  820.   procedure TMyMDIFrame.idDialog1(var Msg:  TMessage);
  821.     begin    { TMyMDIFrame.idDialog1 }
  822.       DialogType := Dialog1;
  823.       CreateChild
  824.     end        { TMyMDIFrame.idDialog1 };
  825.  
  826.   procedure TMyMDIFrame.idDialog2(var Msg:  TMessage);
  827.     begin    { TMyMDIFrame.idDialog2 }
  828.       DialogType := Dialog2;
  829.       CreateChild
  830.     end        { TMyMDIFrame.idDialog2 };
  831.  
  832.   procedure TMyMDIFrame.idEditCtrl(var Msg:  TMessage);
  833.     begin    { TMyMDIFrame.idEditCtrl }
  834.       DialogType := EditCtrl;
  835.       CreateChild
  836.     end        { TMyMDIFrame.idDialog2 };
  837.  
  838.   procedure TMyMDIFrame.idRandRect(var Msg:  TMessage);
  839.     begin    { TMyMDIFrame.idRandRect }
  840.       DialogType := RandRect;
  841.       CreateChild
  842.     end        { TMyMDIFrame.idRandRect };
  843.  
  844. {**********************************************************************
  845.  
  846.     This method creates the appropriate MDI child window by testing
  847.         the value of the frame window's DialogType field.  The idea is
  848.         that we need to make sure that the proper type of child window
  849.         is created, and we only have one routine that can do it, so
  850.         we test the value of the field to figure out which type to
  851.         create.
  852.  
  853. **********************************************************************}
  854.  
  855.   function TMyMDIFrame.InitChild:  PWindowsObject;
  856.     var
  857.       Num  : Integer;
  858.       Temp :  string[31];
  859.       Title:  array [0 .. 32] of char;
  860.       Temp2:  array [0 .. 10] of char;
  861.  
  862.  
  863.     function NumberUsed(P: PWindow): Boolean; far;
  864.       begin    { NumberUsed }
  865.         NumberUsed := Num = P^.Attr.ID
  866.       end    { NumberUsed };
  867.  
  868.     begin    { TMyMDIFrame.InitChild }
  869.       Inc(NoChildren);
  870.       Num := 1;
  871.       while FirstThat(@NumberUsed) <> nil do
  872.         Inc(Num);
  873.       StrCopy(Title, ChildTitles[DialogType]);
  874.       Str(Num:1, Temp);
  875.       StrCat(Title, StrPCopy(Temp2, Temp));
  876.       case DialogType of
  877.         Dialog1 :  InitChild := New(PMDIDialog1  , Init(@Self, Title, Num));
  878.         Dialog2 :  InitChild := New(PMDIDialog2  , Init(@Self, Title, Num));
  879.         RandRect:  InitChild := New(PRandRect    , Init(@Self, Title, Num));
  880.         EditCtrl:  InitChild := New(PMDIEditChild, Init(@Self, Title, Num))
  881.       end
  882.     end        { TMyMDIFrame.InitChild };
  883.  
  884. {**********************************************************************
  885.  
  886.     TRandRect methods
  887.  
  888.         Init constructor.  This routine initializes the fields we've
  889.         added to the inherited set and then calls the inherited
  890.         constructor to build the window.
  891.  
  892. **********************************************************************}
  893.  
  894.   constructor TRandRect.Init(AParent:  PWindowsObject;
  895.                              ATitle :  PChar;
  896.                              ANumber:  integer);
  897.     begin    { TRandRect.Init }
  898.       with MDIApplication do
  899.         TMDIChild.Init(AParent, ATitle, RectMenu, RectPos);
  900.       Attr.ID := ANumber
  901.     end        { TRandRect.Init };
  902.  
  903. {**********************************************************************
  904.  
  905.     These two methods are standard for changing the window class's
  906.         characteristics.  In this case, we name the class "RandRect".
  907.         We also set the class's icon to the icon we created in the
  908.         resource file.  This allows us to use the standard windows
  909.         code for dealing with a minimized instance of this class!
  910.  
  911. **********************************************************************}
  912.  
  913.   function TRandRect.GetClassName:  PChar;
  914.     begin    { TMDIEditChild.GetClassName }
  915.       GetClassName := RandName
  916.     end        { TMDIRandRect.GetClassName };
  917.  
  918.   procedure TRandRect.SetupWindow;
  919.     begin    { TRandRect.SetupWindow }
  920.       TMDIChild.SetupWindow;
  921.       SetTimer(HWindow, 1, 250, nil)
  922.     end        { TRandRect.SetupWindow };
  923.  
  924. {**********************************************************************
  925.  
  926.     The following methods were taken from Charles Petzold's MDI
  927.         Demo example program and translated to OWL.
  928.  
  929. **********************************************************************}
  930.  
  931.   procedure TRandRect.wmDestroy(var Msg:  TMessage);
  932.     begin    { TRandRect.wmDestroy }
  933.       KillTimer(HWindow, 1);
  934.       TWindow.wmDestroy(Msg)
  935.     end        { TRandRect.wmDestroy };
  936.  
  937.   procedure TRandRect.wmPaint(var Msg:  TMessage);
  938.     var
  939.       DC:  HDC;
  940.       PS:  TPaintStruct;
  941.  
  942.     begin    { TRandRect.Paint }
  943.       InvalidateRect(HWindow, nil, TRUE);
  944.       DC := BeginPaint(HWindow, PS);
  945.       EndPaint(HWindow, PS);
  946.       Msg.Result := 0
  947.     end        { TRandRect.Paint };
  948.  
  949.   procedure TRandRect.wmTimer(var Msg:  TMessage);
  950.     var
  951.       Brush  ,
  952.       OBrush :  HBrush;
  953.       DC     :  HDC;
  954.       Blue   ,
  955.       Green  ,
  956.       Red    ,
  957.       xLeft  ,
  958.       xRight ,
  959.       yTop   ,
  960.       yBottom:  integer;
  961.  
  962.       function Max(a, b:  integer):  integer;
  963.         begin    { Max }
  964.           if a > b
  965.             then Max := a
  966.             else Max := b
  967.         end    { Max };
  968.  
  969.       function Min(a, b:  integer):  integer;
  970.         begin    { Min }
  971.           if a < b
  972.             then Min := a
  973.             else Min := b
  974.         end    { Min };
  975.  
  976.     begin    { TRandRect.wmTimer }
  977.       xLeft   := round(random * Attr.W);
  978.       xRight  := round(random * Attr.W);
  979.       yTop    := round(random * Attr.H);
  980.       yBottom := round(random * Attr.H);
  981.       Blue    := round(random * 255);
  982.       Green   := round(random * 255);
  983.       Red     := round(random * 255);
  984.  
  985.       DC     := GetDC(HWindow);
  986.       Brush  := CreateSolidBrush(RGB(Red, Green, Blue));
  987.       OBrush := SelectObject(DC, Brush);
  988.       Rectangle(DC, min(xLeft, xRight), min(yTop, yBottom),
  989.                     max(xLeft, xRight), max(yTop, yBottom));
  990.       SelectObject(DC, OBrush);
  991.       DeleteObject(Brush);
  992.       ReleaseDC(HWindow, DC);
  993.       Msg.Result := 0
  994.     end        { TRandRect.wmTimer };
  995.  
  996. {**********************************************************************
  997.  
  998.     Main program.  Initialize the program, run the message loop,
  999.         then shut it down.
  1000.  
  1001. **********************************************************************}
  1002.  
  1003.   begin        { MDIExample }
  1004.     Randomize;
  1005.     MDIApplication.Init(AppName);
  1006.     MDIApplication.Run;
  1007.     MDIApplication.Done
  1008.   end        { MDIExample }.